import React, { useCallback, useRef, useState } from 'react';

import { ReactComponent as FormatIcon } from '@/assets/images/icon-format.svg';
import { ReactComponent as RedoIcon } from '@/assets/images/icon-redo.svg';
import { ReactComponent as ResetIcon } from '@/assets/images/icon-reset.svg';
import { ReactComponent as RunIcon } from '@/assets/images/icon-run.svg';
import { ReactComponent as SaveIcon } from '@/assets/images/icon-save.svg';
import { ReactComponent as ScreenExitIcon } from '@/assets/images/icon-screen-exit.svg';
import { ReactComponent as ScreenFullIcon } from '@/assets/images/icon-screen-full.svg';
import { ReactComponent as SettingIcon } from '@/assets/images/icon-setting.svg';
import { ReactComponent as TaskIcon } from '@/assets/images/icon-task.svg';
import { ReactComponent as ThemeFillIcon } from '@/assets/images/icon-theme-fill.svg';
import { ReactComponent as ThemeIcon } from '@/assets/images/icon-theme.svg';
import { ReactComponent as UndoIcon } from '@/assets/images/icon-undo.svg';

import { useFullscreen, useSetState } from 'ahooks';
import {
  EditorDefaultConfig,
  EditorThemeList,
  EditorThemeMap,
  ICalculateType,
  IEditorBasicProps,
  IEditorOperateType,
  IEditorProps,
  IEditorRefHandles,
  IOperateGroupItem,
} from './CodeEditorConfig';
import { CodeEditorSetting } from './CodeEditorSetting';
import { EditorLayout } from './CodeEditorStyle';
import { CodeEditorToolbar } from './CodeEditorToolbar';

import { useEffect, useMemo } from 'react';
import { CodeEditorAce } from './CodeEditorAce';
import { CodeEditorCalculate } from './CodeEditorCalculate';
import { CodeEditorMonaco } from './CodeEditorMonaco';

interface Props extends IEditorProps {}

export const CodeEditor: React.FC<Props> = (props) => {
  const {
    value = '',
    editorType,
    language,
    theme,
    fontSize,
    readOnly,
    format,

    completers,
    onChange,
    onLoad,
  } = props;

  const [code, setCode] = useState(value);
  const handleRef = useRef<IEditorRefHandles>();
  const editorWrapRef = useRef(null);

  const [isFullscreen, { toggleFullscreen }] = useFullscreen(editorWrapRef);

  const [editorState, setEditorState] =
    useSetState<Partial<IEditorBasicProps>>(EditorDefaultConfig);

  const [open, setOpen] = useState(false);

  /** 重置编辑器内容 */
  const resetValue = useCallback(() => {
    const value: string = handleRef.current?.getValue() ?? '';

    setCode(value);
  }, []);

  const openDrawer = useCallback(() => {
    setOpen(true);
  }, []);

  const closeDrawer = () => {
    setOpen(false);
  };

  /** 切换是否只读 */
  const handleEditorSettingChange = useCallback(
    (
      value: any,
      type?: keyof IEditorBasicProps | IEditorOperateType | ICalculateType,
    ) => {
      switch (type) {
        case 'undo':
          handleRef.current?.editorEvent({ type: 'undo' });
          break;
        case 'redo':
          handleRef.current?.editorEvent({ type: 'redo' });
          break;
        case 'reset':
          handleRef.current?.setValue('');
          break;
        case 'run':
          handleRef.current?.run();
          break;
        case 'format':
          handleRef.current?.format();
          break;
        case 'screenFull':
          toggleFullscreen();
          break;
        case 'setting':
          openDrawer();
          break;

        default:
          setEditorState({
            [`${type}`]: value,
          });

          resetValue();
          break;
      }
    },
    [resetValue, toggleFullscreen, openDrawer, setEditorState],
  );

  const isLight = editorState.theme === 'light';
  const lastThemeArr = EditorThemeList.filter((v) => v !== editorState.theme);
  const idx = Math.floor(Math.random() * lastThemeArr.length);

  const OperateGroupBtns: IOperateGroupItem[][] = [
    [
      {
        type: 'run',
        label: '运行',
        text: <RunIcon />,
      },
      {
        type: 'task',
        label: '查看执行计划',
        text: <TaskIcon />,
      },
      {
        type: 'save',
        label: '保存',
        text: <SaveIcon />,
      },
      {
        type: 'undo',
        label: '撤销',
        text: <UndoIcon />,
      },
      {
        type: 'redo',
        label: '重做',
        text: <RedoIcon />,
      },
      {
        type: 'reset',
        label: '重置',
        text: <ResetIcon />,
      },
    ],
    [
      {
        type: 'format',
        label: '格式化',
        text: <FormatIcon />,
      },
      {
        type: 'theme',
        label: '更换主题',
        text: isLight ? <ThemeIcon /> : <ThemeFillIcon />,
        value: lastThemeArr[idx],
      },
      {
        type: 'screenFull',
        label: isFullscreen ? '退出全屏' : '全屏',
        text: isFullscreen ? <ScreenExitIcon /> : <ScreenFullIcon />,
      },
      {
        type: 'setting',
        label: '设置',
        text: <SettingIcon />,
      },
    ],
  ];

  const EditorContainer = useMemo(() => {
    if (Object.keys(editorState).length) {
      const editorOptions: IEditorProps = {
        ...editorState,
        handleRef,
        completers,
        value: code,
        theme:
          EditorThemeMap[editorState?.editorType as any][editorState?.theme],
        onChange,
        onLoad: () => {
          // 这里需要延迟一下，不然获取不到handleRef
          setTimeout(() => {
            if (onLoad && handleRef.current) {
              onLoad(handleRef.current);
            }
          }, 0);
        },
      };

      return editorState?.editorType === 'ace' ? (
        <CodeEditorAce {...editorOptions} />
      ) : (
        <CodeEditorMonaco {...editorOptions} />
      );
    }
  }, [editorState, onChange, onLoad, completers, code]);

  useEffect(() => {
    const filteredObj = Object.entries({
      editorType,
      language,
      theme,
      fontSize,
      readOnly,
      format,
    })
      .filter(([, value]) => value !== undefined)
      .reduce((obj, [key, value]) => Object.assign(obj, { [key]: value }), {});
    const targetObj = Object.assign({}, filteredObj);

    setEditorState((preState) => {
      return { ...preState, ...targetObj };
    });
  }, [editorType, language, theme, fontSize, readOnly, format, setEditorState]);

  return (
    <EditorLayout ref={editorWrapRef}>
      <div className="editor-head">
        <div className="editor-head-content">
          <CodeEditorCalculate
            isFunc
            editor={handleRef?.current}
            editorType={editorState?.editorType}
            readOnly={readOnly}
          />
        </div>

        <div className="editor-head-extra">
          <CodeEditorCalculate
            editor={handleRef?.current}
            editorType={editorState?.editorType}
            readOnly={readOnly}
          />

          <CodeEditorToolbar
            size={'small'}
            data={OperateGroupBtns}
            callback={handleEditorSettingChange}
          />
        </div>
      </div>
      <div className="editor-body">{EditorContainer}</div>
      {open && (
        <CodeEditorSetting
          editorProps={editorState}
          onClose={closeDrawer}
          callback={handleEditorSettingChange}
        />
      )}
    </EditorLayout>
  );
};
